home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / BeOS / main_beos.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-10  |  19.0 KB  |  798 lines

  1. /*
  2.  *  main_beos.cpp - Startup code for BeOS
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <AppKit.h>
  22. #include <InterfaceKit.h>
  23. #include <KernelKit.h>
  24. #include <StorageKit.h>
  25.  
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. #include <signal.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <time.h>
  32.  
  33. #include "sysdeps.h"
  34. #include "cpu_emulation.h"
  35. #include "xpram.h"
  36. #include "timer.h"
  37. #include "video.h"
  38. #include "rom_patches.h"
  39. #include "prefs.h"
  40. #include "prefs_editor.h"
  41. #include "sys.h"
  42. #include "user_strings.h"
  43. #include "version.h"
  44. #include "main.h"
  45.  
  46. #include "sheep_driver.h"
  47.  
  48. #define DEBUG 0
  49. #include "debug.h"
  50.  
  51.  
  52. // Constants
  53. const char APP_SIGNATURE[] = "application/x-vnd.cebix-BasiliskII";
  54. const char ROM_FILE_NAME[] = "ROM";
  55. const char RAM_AREA_NAME[] = "Macintosh RAM";
  56. const char ROM_AREA_NAME[] = "Macintosh ROM";
  57. const uint32 MSG_START = 'strt';            // Emulator start message
  58. const uint32 ROM_AREA_SIZE = 0x500000;        // Enough to hold PowerMac ROM (for powerrom_cpu)
  59.  
  60. // Prototypes
  61. #if __POWERPC__
  62. static void sigsegv_handler(vregs *r);
  63. #endif
  64.  
  65.  
  66. // Application object
  67. class BasiliskII : public BApplication {
  68. public:
  69.     BasiliskII() : BApplication(APP_SIGNATURE)
  70.     {
  71.         // Find application directory and cwd to it
  72.         app_info the_info;
  73.         GetAppInfo(&the_info);
  74.         BEntry the_file(&the_info.ref);
  75.         BEntry the_dir;
  76.         the_file.GetParent(&the_dir);
  77.         BPath the_path;
  78.         the_dir.GetPath(&the_path);
  79.         chdir(the_path.Path());
  80.  
  81.         // Initialize other variables
  82.         rom_area = ram_area = -1;
  83.         xpram_thread = tick_thread = -1;
  84.         xpram_thread_active = true;
  85.         tick_thread_active = true;
  86.         AllowQuitting = true;
  87.     }
  88.     virtual void ReadyToRun(void);
  89.     virtual void MessageReceived(BMessage *msg);
  90.     void StartEmulator(void);
  91.     virtual bool QuitRequested(void);
  92.     virtual void Quit(void);
  93.  
  94.     thread_id xpram_thread;        // XPRAM watchdog
  95.     thread_id tick_thread;        // 60Hz thread
  96.  
  97.     volatile bool xpram_thread_active;    // Flag for quitting the XPRAM thread
  98.     volatile bool tick_thread_active;    // Flag for quitting the 60Hz thread
  99.  
  100.     bool AllowQuitting;            // Flag: Alt-Q quitting allowed
  101.  
  102. private:
  103.     static status_t emul_func(void *arg);
  104.     static status_t tick_func(void *arg);
  105.     static status_t xpram_func(void *arg);
  106.     static void sigsegv_invoc(int sig, void *arg, vregs *r);
  107.  
  108.     void init_rom(void);
  109.     void load_rom(void);
  110.  
  111.     area_id rom_area;        // ROM area ID
  112.     area_id ram_area;        // RAM area ID
  113.  
  114.     struct sigaction sigsegv_action;    // Data access exception signal (of emulator thread)
  115.  
  116.     // Exceptions
  117.     class area_error {};
  118.     class file_open_error {};
  119.     class file_read_error {};
  120.     class rom_size_error {};
  121. };
  122.  
  123. static BasiliskII *the_app;
  124.  
  125.  
  126. // CPU and FPU type, addressing mode
  127. int CPUType;
  128. bool CPUIs68060;
  129. int FPUType;
  130. bool TwentyFourBitAddressing;
  131.  
  132.  
  133. // Global variables for PowerROM CPU
  134. thread_id emul_thread = -1;            // Emulator thread
  135.  
  136. #if __POWERPC__
  137. int sheep_fd = -1;                    // fd of sheep driver
  138. #endif
  139.  
  140.  
  141. /*
  142.  *  Create application object and start it
  143.  */
  144.  
  145. int main(int argc, char **argv)
  146. {    
  147.     the_app = new BasiliskII();
  148.     the_app->Run();
  149.     delete the_app;
  150.     return 0;
  151. }
  152.  
  153.  
  154. /*
  155.  *  Run application
  156.  */
  157.  
  158. void BasiliskII::ReadyToRun(void)
  159. {
  160.     // Initialize variables
  161.     RAMBaseHost = NULL;
  162.     ROMBaseHost = NULL;
  163.     srand(real_time_clock());
  164.     tzset();
  165.  
  166.     // Print some info
  167.     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
  168.     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
  169.  
  170.     // Delete old areas
  171.     area_id old_ram_area = find_area(RAM_AREA_NAME);
  172.     if (old_ram_area > 0)
  173.         delete_area(old_ram_area);
  174.     area_id old_rom_area = find_area(ROM_AREA_NAME);
  175.     if (old_rom_area > 0)
  176.         delete_area(old_rom_area);
  177.  
  178.     // Read preferences
  179.     int argc = 0;
  180.     char **argv = NULL;
  181.     PrefsInit(argc, argv);
  182.  
  183.     // Init system routines
  184.     SysInit();
  185.  
  186.     // Show preferences editor (or start emulator directly)
  187.     if (!PrefsFindBool("nogui"))
  188.         PrefsEditor();
  189.     else
  190.         PostMessage(MSG_START);
  191. }
  192.  
  193.  
  194. /*
  195.  *  Message received
  196.  */
  197.  
  198. void BasiliskII::MessageReceived(BMessage *msg)
  199. {
  200.     switch (msg->what) {
  201.         case MSG_START:
  202.             StartEmulator();
  203.             break;
  204.         default:
  205.             BApplication::MessageReceived(msg);
  206.     }
  207. }
  208.  
  209.  
  210. /*
  211.  *  Start emulator
  212.  */
  213.  
  214. void BasiliskII::StartEmulator(void)
  215. {
  216.     char str[256];
  217.  
  218. #if REAL_ADDRESSING
  219.     // Open sheep driver and remap low memory
  220.     sheep_fd = open("/dev/sheep", 0);
  221.     if (sheep_fd < 0) {
  222.         sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd);
  223.         ErrorAlert(str);
  224.         PostMessage(B_QUIT_REQUESTED);
  225.         return;
  226.     }
  227.     status_t res = ioctl(sheep_fd, SHEEP_UP);
  228.     if (res < 0) {
  229.         sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res);
  230.         ErrorAlert(str);
  231.         PostMessage(B_QUIT_REQUESTED);
  232.         return;
  233.     }
  234. #endif
  235.  
  236.     // Create area for Mac RAM
  237.     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;    // Round down to 1MB boundary
  238.     if (RAMSize < 1024*1024) {
  239.         WarningAlert(GetString(STR_SMALL_RAM_WARN));
  240.         RAMSize = 1024*1024;
  241.     }
  242.  
  243.     RAMBaseHost = (uint8 *)0x10000000;
  244.     ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBaseHost, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
  245.     if (ram_area < 0) {
  246.         ErrorAlert(GetString(STR_NO_RAM_AREA_ERR));
  247.         PostMessage(B_QUIT_REQUESTED);
  248.         return;
  249.     }
  250.     D(bug("RAM area %ld at %p\n", ram_area, RAMBaseHost));
  251.  
  252.     // Create area and load Mac ROM
  253.     try {
  254.         init_rom();
  255.     } catch (area_error) {
  256.         ErrorAlert(GetString(STR_NO_ROM_AREA_ERR));
  257.         PostMessage(B_QUIT_REQUESTED);
  258.         return;
  259.     } catch (file_open_error) {
  260.         ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
  261.         PostMessage(B_QUIT_REQUESTED);
  262.         return;
  263.     } catch (file_read_error) {
  264.         ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
  265.         PostMessage(B_QUIT_REQUESTED);
  266.         return;
  267.     } catch (rom_size_error) {
  268.         ErrorAlert(GetString(STR_ROM_SIZE_ERR));
  269.         PostMessage(B_QUIT_REQUESTED);
  270.         return;
  271.     }
  272.  
  273.     // Initialize everything
  274.     if (!InitAll()) {
  275.         PostMessage(B_QUIT_REQUESTED);
  276.         return;
  277.     }
  278.  
  279.     // Write protect ROM
  280.     set_area_protection(rom_area, B_READ_AREA);
  281.  
  282.     // Disallow quitting with Alt-Q from now on
  283.     AllowQuitting = false;
  284.  
  285.     // Start XPRAM watchdog thread
  286.     xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this);
  287.     resume_thread(xpram_thread);
  288.  
  289.     // Start 60Hz interrupt
  290.     tick_thread = spawn_thread(tick_func, "60Hz", B_REAL_TIME_PRIORITY, this);
  291.     resume_thread(tick_thread);
  292.  
  293.     // Start emulator thread
  294.     emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this);
  295.     resume_thread(emul_thread);
  296. }
  297.  
  298.  
  299. /*
  300.  *  Quit emulator
  301.  */
  302.  
  303. void QuitEmulator(void)
  304. {
  305.     the_app->AllowQuitting = true;
  306.     be_app->PostMessage(B_QUIT_REQUESTED);
  307.     exit_thread(0);
  308. }
  309.  
  310. bool BasiliskII::QuitRequested(void)
  311. {
  312.     if (AllowQuitting)
  313.         return BApplication::QuitRequested();
  314.     else
  315.         return false;
  316. }
  317.  
  318. void BasiliskII::Quit(void)
  319. {
  320.     status_t l;
  321.  
  322.     // Stop 60Hz interrupt
  323.     if (tick_thread > 0) {
  324.         tick_thread_active = false;
  325.         wait_for_thread(tick_thread, &l);
  326.     }
  327.  
  328.     // Wait for emulator thread to finish
  329.     if (emul_thread > 0)
  330.         wait_for_thread(emul_thread, &l);
  331.  
  332.     // Exit 680x0 emulation
  333.     Exit680x0();
  334.  
  335.     // Stop XPRAM watchdog thread
  336.     if (xpram_thread > 0) {
  337.         xpram_thread_active = false;
  338.         suspend_thread(xpram_thread);    // Wake thread up from snooze()
  339.         snooze(1000);
  340.         resume_thread(xpram_thread);
  341.         wait_for_thread(xpram_thread, &l);
  342.     }
  343.  
  344.     // Deinitialize everything
  345.     ExitAll();
  346.  
  347.     // Delete ROM area
  348.     if (rom_area >= 0)
  349.         delete_area(rom_area);
  350.  
  351.     // Delete RAM area
  352.     if (ram_area >= 0)
  353.         delete_area(ram_area);
  354.  
  355. #if REAL_ADDRESSING
  356.     // Unmap low memory and close memory mess driver
  357.     if (sheep_fd >= 0) {
  358.         ioctl(sheep_fd, SHEEP_DOWN);
  359.         close(sheep_fd);
  360.     }
  361. #endif
  362.  
  363.     // Exit system routines
  364.     SysExit();
  365.  
  366.     // Exit preferences
  367.     PrefsExit();
  368.  
  369.     BApplication::Quit();
  370. }
  371.  
  372.  
  373. /*
  374.  *  Create area for ROM (sets rom_area) and load ROM file
  375.  *
  376.  *  area_error     : Cannot create area
  377.  *  file_open_error: Cannot open ROM file
  378.  *  file_read_error: Cannot read ROM file
  379.  */
  380.  
  381. void BasiliskII::init_rom(void)
  382. {
  383.     // Create area for ROM
  384.     ROMBaseHost = (uint8 *)0x40800000;
  385.     rom_area = create_area(ROM_AREA_NAME, (void **)&ROMBaseHost, B_BASE_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
  386.     if (rom_area < 0)
  387.         throw area_error();
  388.     D(bug("ROM area %ld at %p\n", rom_area, ROMBaseHost));
  389.  
  390.     // Load ROM
  391.     load_rom();
  392. }
  393.  
  394.  
  395. /*
  396.  *  Load ROM file
  397.  *
  398.  *  file_open_error: Cannot open ROM file
  399.  *  file_read_error: Cannot read ROM file
  400.  */
  401.  
  402. void BasiliskII::load_rom(void)
  403. {
  404.     // Get rom file path from preferences
  405.     const char *rom_path = PrefsFindString("rom");
  406.  
  407.     // Try to open ROM file
  408.     BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
  409.     if (file.InitCheck() != B_NO_ERROR)
  410.         throw file_open_error();
  411.  
  412.     printf(GetString(STR_READING_ROM_FILE));
  413.  
  414.     // Is the ROM size correct?
  415.     off_t rom_size = 0;
  416.     file.GetSize(&rom_size);
  417.     if (rom_size != 64*1024 && rom_size != 128*1024 && rom_size != 256*1024 && rom_size != 512*1024 && rom_size != 1024*1024)
  418.         throw rom_size_error();
  419.  
  420.     uint8 *rom = new uint8[rom_size];    // Reading directly into the area doesn't work
  421.     ssize_t actual = file.Read((void *)rom, rom_size);
  422.     if (actual == rom_size)
  423.         memcpy(ROMBaseHost, rom, rom_size);
  424.     delete[] rom;
  425.     if (actual != rom_size)
  426.         throw file_read_error();
  427.     ROMSize = rom_size;
  428. }
  429.  
  430.  
  431. /*
  432.  *  Emulator thread function
  433.  */
  434.  
  435. status_t BasiliskII::emul_func(void *arg)
  436. {
  437.     BasiliskII *obj = (BasiliskII *)arg;
  438.  
  439. #if __POWERPC__
  440.     // Install data access signal handler
  441.     sigemptyset(&obj->sigsegv_action.sa_mask);
  442.     obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
  443.     obj->sigsegv_action.sa_flags = 0;
  444.     obj->sigsegv_action.sa_userdata = arg;
  445.     sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
  446. #endif
  447.  
  448.     // Exceptions will send signals
  449.     disable_debugger(true);
  450.  
  451.     // Start 68k and jump to ROM boot routine
  452.     Start680x0();
  453.  
  454.     // Quit program
  455.     obj->AllowQuitting = true;
  456.     be_app->PostMessage(B_QUIT_REQUESTED);
  457.     return 0;
  458. }
  459.  
  460.  
  461. /*
  462.  *  Code was patched, flush caches if neccessary (i.e. when using a real 680x0
  463.  *  or a dynamically recompiling emulator)
  464.  */
  465.  
  466. void FlushCodeCache(void *start, uint32 size)
  467. {
  468. }
  469.  
  470.  
  471. /*
  472.  *  Interrupt flags (must be handled atomically!)
  473.  */
  474.  
  475. uint32 InterruptFlags = 0;
  476.  
  477. void SetInterruptFlag(uint32 flag)
  478. {
  479.     atomic_or((int32 *)&InterruptFlags, flag);
  480. }
  481.  
  482. void ClearInterruptFlag(uint32 flag)
  483. {
  484.     atomic_and((int32 *)&InterruptFlags, ~flag);
  485. }
  486.  
  487.  
  488. /*
  489.  *  60Hz thread (really 60.15Hz)
  490.  */
  491.  
  492. status_t BasiliskII::tick_func(void *arg)
  493. {
  494.     BasiliskII *obj = (BasiliskII *)arg;
  495.     int tick_counter = 0;
  496.     bigtime_t current = system_time();
  497.  
  498.     while (obj->tick_thread_active) {
  499.  
  500.         // Wait
  501.         current += 16625;
  502.         snooze_until(current, B_SYSTEM_TIMEBASE);
  503.  
  504.         // Pseudo Mac 1Hz interrupt, update local time
  505.         if (++tick_counter > 60) {
  506.             tick_counter = 0;
  507.             WriteMacInt32(0x20c, TimerDateTime());
  508.             SetInterruptFlag(INTFLAG_1HZ);
  509.             TriggerInterrupt();
  510.         }
  511.  
  512.         // Trigger 60Hz interrupt
  513.         SetInterruptFlag(INTFLAG_60HZ);
  514.         TriggerInterrupt();
  515.     }
  516.     return 0;
  517. }
  518.  
  519.  
  520. /*
  521.  *  XPRAM watchdog thread (saves XPRAM every minute)
  522.  */
  523.  
  524. status_t BasiliskII::xpram_func(void *arg)
  525. {
  526.     uint8 last_xpram[256];
  527.     memcpy(last_xpram, XPRAM, 256);
  528.  
  529.     while (((BasiliskII *)arg)->xpram_thread_active) {
  530.         snooze(60*1000000);
  531.         if (memcmp(last_xpram, XPRAM, 256)) {
  532.             memcpy(last_xpram, XPRAM, 256);
  533.             SaveXPRAM();
  534.         }
  535.     }
  536.     return 0;
  537. }
  538.  
  539.  
  540. /*
  541.  *  Display error alert
  542.  */
  543.  
  544. void ErrorAlert(const char *text)
  545. {
  546.     if (PrefsFindBool("nogui")) {
  547.         printf(GetString(STR_SHELL_ERROR_PREFIX), text);
  548.         return;
  549.     }
  550.     VideoQuitFullScreen();
  551.     char str[256];
  552.     sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
  553.     BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
  554.     alert->Go();
  555. }
  556.  
  557.  
  558. /*
  559.  *  Display warning alert
  560.  */
  561.  
  562. void WarningAlert(const char *text)
  563. {
  564.     if (PrefsFindBool("nogui")) {
  565.         printf(GetString(STR_SHELL_WARNING_PREFIX), text);
  566.         return;
  567.     }
  568.     char str[256];
  569.     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
  570.     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
  571.     alert->Go();
  572. }
  573.  
  574.  
  575. /*
  576.  *  Display choice alert
  577.  */
  578.  
  579. bool ChoiceAlert(const char *text, const char *pos, const char *neg)
  580. {
  581.     char str[256];
  582.     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
  583.     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
  584.     return alert->Go() == 0;
  585. }
  586.  
  587.  
  588. /*
  589.  *  SEGV handler
  590.  */
  591.  
  592. #if __POWERPC__
  593. static uint32 segv_r[32];
  594.  
  595. asm void BasiliskII::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
  596. {
  597.     mflr    r0
  598.     stw        r0,8(r1)
  599.     stwu    r1,-56(r1)
  600.  
  601.     lwz        r3,segv_r(r2)
  602.     stmw    r13,13*4(r3)
  603.  
  604.     mr        r3,r5
  605.     bl        sigsegv_handler
  606.  
  607.     lwz        r3,segv_r(r2)
  608.     lmw        r13,13*4(r3)
  609.  
  610.     lwz        r0,56+8(r1)
  611.     mtlr    r0
  612.     addi    r1,r1,56
  613.     blr
  614. }
  615.  
  616. static void sigsegv_handler(vregs *r)
  617. {
  618.     // Fetch volatile registers
  619.     segv_r[0] = r->r0;
  620.     segv_r[1] = r->r1;
  621.     segv_r[2] = r->r2;
  622.     segv_r[3] = r->r3;
  623.     segv_r[4] = r->r4;
  624.     segv_r[5] = r->r5;
  625.     segv_r[6] = r->r6;
  626.     segv_r[7] = r->r7;
  627.     segv_r[8] = r->r8;
  628.     segv_r[9] = r->r9;
  629.     segv_r[10] = r->r10;
  630.     segv_r[11] = r->r11;
  631.     segv_r[12] = r->r12;
  632.  
  633.     // Get opcode and divide into fields
  634.     uint32 opcode = *(uint32 *)r->pc;
  635.     uint32 primop = opcode >> 26;
  636.     uint32 exop = (opcode >> 1) & 0x3ff;
  637.     uint32 ra = (opcode >> 16) & 0x1f;
  638.     uint32 rb = (opcode >> 11) & 0x1f;
  639.     uint32 rd = (opcode >> 21) & 0x1f;
  640.     uint32 imm = opcode & 0xffff;
  641.  
  642.     // Analyze opcode
  643.     enum {
  644.         TYPE_UNKNOWN,
  645.         TYPE_LOAD,
  646.         TYPE_STORE
  647.     } transfer_type = TYPE_UNKNOWN;
  648.     enum {
  649.         SIZE_UNKNOWN,
  650.         SIZE_BYTE,
  651.         SIZE_HALFWORD,
  652.         SIZE_WORD
  653.     } transfer_size = SIZE_UNKNOWN;
  654.     enum {
  655.         MODE_UNKNOWN,
  656.         MODE_NORM,
  657.         MODE_U,
  658.         MODE_X,
  659.         MODE_UX
  660.     } addr_mode = MODE_UNKNOWN;
  661.     switch (primop) {
  662.         case 31:
  663.             switch (exop) {
  664.                 case 23:    // lwzx
  665.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
  666.                 case 55:    // lwzux
  667.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
  668.                 case 87:    // lbzx
  669.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
  670.                 case 119:    // lbzux
  671.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
  672.                 case 151:    // stwx
  673.                     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
  674.                 case 183:    // stwux
  675.                     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
  676.                 case 215:    // stbx
  677.                     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
  678.                 case 247:    // stbux
  679.                     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
  680.                 case 279:    // lhzx
  681.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
  682.                 case 311:    // lhzux
  683.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
  684.                 case 343:    // lhax
  685.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
  686.                 case 375:    // lhaux
  687.                     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
  688.                 case 407:    // sthx
  689.                     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
  690.                 case 439:    // sthux
  691.                     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
  692.             }
  693.             break;
  694.  
  695.         case 32:    // lwz
  696.             transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
  697.         case 33:    // lwzu
  698.             transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
  699.         case 34:    // lbz
  700.             transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
  701.         case 35:    // lbzu
  702.             transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
  703.         case 36:    // stw
  704.             transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
  705.         case 37:    // stwu
  706.             transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
  707.         case 38:    // stb
  708.             transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
  709.         case 39:    // stbu
  710.             transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
  711.         case 40:    // lhz
  712.             transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
  713.         case 41:    // lhzu
  714.             transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
  715.         case 42:    // lha
  716.             transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
  717.         case 43:    // lhau
  718.             transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
  719.         case 44:    // sth
  720.             transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
  721.         case 45:    // sthu
  722.             transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
  723.     }
  724.  
  725.     // Calculate effective address
  726.     uint32 addr = 0;
  727.     switch (addr_mode) {
  728.         case MODE_X:
  729.         case MODE_UX:
  730.             if (ra == 0)
  731.                 addr = segv_r[rb];
  732.             else
  733.                 addr = segv_r[ra] + segv_r[rb];
  734.             break;
  735.         case MODE_NORM:
  736.         case MODE_U:
  737.             if (ra == 0)
  738.                 addr = (int32)(int16)imm;
  739.             else
  740.                 addr = segv_r[ra] + (int32)(int16)imm;
  741.             break;
  742.     }
  743.  
  744.     // Ignore ROM writes
  745.     if (transfer_type == TYPE_STORE && addr >= (uint32)ROMBaseHost && addr < (uint32)ROMBaseHost + ROMSize) {
  746. //        D(bug("WARNING: %s write access to ROM at %p, 68k pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc));
  747.         if (addr_mode == MODE_U || addr_mode == MODE_UX)
  748.             segv_r[ra] = addr;
  749.         r->pc += 4;
  750.         goto rti;
  751.     }
  752.  
  753.     // For all other errors, jump into debugger
  754.     char str[256];
  755.     sprintf(str, "SIGSEGV\n"
  756.         "   pc %08lx     lr %08lx    ctr %08lx    msr %08lx\n"
  757.         "  xer %08lx     cr %08lx  fpscr %08lx\n"
  758.         "   r0 %08lx     r1 %08lx     r2 %08lx     r3 %08lx\n"
  759.         "   r4 %08lx     r5 %08lx     r6 %08lx     r7 %08lx\n"
  760.         "   r8 %08lx     r9 %08lx    r10 %08lx    r11 %08lx\n"
  761.         "  r12 %08lx    r13 %08lx    r14 %08lx    r15 %08lx\n"
  762.         "  r16 %08lx    r17 %08lx    r18 %08lx    r19 %08lx\n"
  763.         "  r20 %08lx    r21 %08lx    r22 %08lx    r23 %08lx\n"
  764.         "  r24 %08lx    r25 %08lx    r26 %08lx    r27 %08lx\n"
  765.         "  r28 %08lx    r29 %08lx    r30 %08lx    r31 %08lx\n",
  766.         r->pc, r->lr, r->ctr, r->msr,
  767.         r->xer, r->cr, r->fpscr,
  768.         r->r0, r->r1, r->r2, r->r3,
  769.         r->r4, r->r5, r->r6, r->r7,
  770.         r->r8, r->r9, r->r10, r->r11,
  771.         r->r12, segv_r[13], segv_r[14], segv_r[15],
  772.         segv_r[16], segv_r[17], segv_r[18], segv_r[19],
  773.         segv_r[20], segv_r[21], segv_r[22], segv_r[23],
  774.         segv_r[24], segv_r[25], segv_r[26], segv_r[27],
  775.         segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
  776.     disable_debugger(false);
  777.     debugger(str);
  778.     QuitEmulator();
  779.     return;
  780.  
  781. rti:
  782.     // Restore volatile registers
  783.     r->r0 = segv_r[0];
  784.     r->r1 = segv_r[1];
  785.     r->r2 = segv_r[2];
  786.     r->r3 = segv_r[3];
  787.     r->r4 = segv_r[4];
  788.     r->r5 = segv_r[5];
  789.     r->r6 = segv_r[6];
  790.     r->r7 = segv_r[7];
  791.     r->r8 = segv_r[8];
  792.     r->r9 = segv_r[9];
  793.     r->r10 = segv_r[10];
  794.     r->r11 = segv_r[11];
  795.     r->r12 = segv_r[12];
  796. }
  797. #endif
  798.